/*
===========================================================================
Copyright (C) 1999-2005 Id Software, Inc.
 
This file is part of Quake III Arena source code.
 
Quake III Arena source code is free software; you can redistribute it
and/or modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of the License,
or (at your option) any later version.
 
Quake III Arena source code is distributed in the hope that it will be
useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.
 
You should have received a copy of the GNU General Public License
along with Foobar; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
===========================================================================
*/
//
#include "ui_local.h"

void GraphicsOptions_MenuInit( void );

/*
=======================================================================
 
DRIVER INFORMATION MENU
 
=======================================================================
*/


#define DRIVERINFO_FRAMEL	"menu/art/frame2_l"
#define DRIVERINFO_FRAMER	"menu/art/frame1_r"
#define DRIVERINFO_BACK0	"menu/art/back_0"
#define DRIVERINFO_BACK1	"menu/art/back_1"

static char* driverinfo_artlist[] =
    {
        DRIVERINFO_FRAMEL,
        DRIVERINFO_FRAMER,
        DRIVERINFO_BACK0,
        DRIVERINFO_BACK1,
        NULL,
    };

#define ID_DRIVERINFOBACK	100

typedef struct
{
    menuframework_s	menu;
    menutext_s		banner;
    menubitmap_s	back;
    menubitmap_s	framel;
    menubitmap_s	framer;
    char			stringbuff[1024];
    char*			strings[64];
    int				numstrings;
}
driverinfo_t;

static driverinfo_t	s_driverinfo;

/*
=================
DriverInfo_Event
=================
*/
static void DriverInfo_Event( void* ptr, int event )
{
    if (event != QM_ACTIVATED)
        return;

    switch (((menucommon_s*)ptr)->id)
    {
    case ID_DRIVERINFOBACK:
        UI_PopMenu();
        break;
    }
}

/*
=================
DriverInfo_MenuDraw
=================
*/
static void DriverInfo_MenuDraw( void )
{
    int	i;
    int	y;

    Menu_Draw( &s_driverinfo.menu );

    UI_DrawString( 320, 80, "VENDOR", UI_CENTER|UI_SMALLFONT, color_red );
    UI_DrawString( 320, 152, "PIXELFORMAT", UI_CENTER|UI_SMALLFONT, color_red );
    UI_DrawString( 320, 192, "EXTENSIONS", UI_CENTER|UI_SMALLFONT, color_red );

    UI_DrawString( 320, 80+16, uis.glconfig.vendor_string, UI_CENTER|UI_SMALLFONT, text_color_normal );
    UI_DrawString( 320, 96+16, uis.glconfig.version_string, UI_CENTER|UI_SMALLFONT, text_color_normal );
    UI_DrawString( 320, 112+16, uis.glconfig.renderer_string, UI_CENTER|UI_SMALLFONT, text_color_normal );
    UI_DrawString( 320, 152+16, va ("color(%d-bits) Z(%d-bits) stencil(%d-bits)", uis.glconfig.colorBits, uis.glconfig.depthBits, uis.glconfig.stencilBits), UI_CENTER|UI_SMALLFONT, text_color_normal );

    // double column
    y = 192+16;
    for (i=0; i<s_driverinfo.numstrings/2; i++)
    {
        UI_DrawString( 320-4, y, s_driverinfo.strings[i*2], UI_RIGHT|UI_SMALLFONT, text_color_normal );
        UI_DrawString( 320+4, y, s_driverinfo.strings[i*2+1], UI_LEFT|UI_SMALLFONT, text_color_normal );
        y += SMALLCHAR_HEIGHT;
    }

    if (s_driverinfo.numstrings & 1)
        UI_DrawString( 320, y, s_driverinfo.strings[s_driverinfo.numstrings-1], UI_CENTER|UI_SMALLFONT, text_color_normal );
}

/*
=================
DriverInfo_Cache
=================
*/
void DriverInfo_Cache( void )
{
    int	i;

    // touch all our pics
    for (i=0; ;i++)
    {
        if (!driverinfo_artlist[i])
            break;
        RE_RegisterShaderNoMip(driverinfo_artlist[i]);
    }
}

/*
=================
UI_DriverInfo_Menu
=================
*/
static void UI_DriverInfo_Menu( void )
{
    char*	eptr;
    int		i;
    int		len;

    // zero set all our globals
    memset( &s_driverinfo, 0 ,sizeof(driverinfo_t) );

    DriverInfo_Cache();

    s_driverinfo.menu.fullscreen = qtrue;
    s_driverinfo.menu.draw       = DriverInfo_MenuDraw;

    s_driverinfo.banner.generic.type  = MTYPE_BTEXT;
    s_driverinfo.banner.generic.x	  = 320;
    s_driverinfo.banner.generic.y	  = 16;
    s_driverinfo.banner.string		  = "DRIVER INFO";
    s_driverinfo.banner.color	      = color_white;
    s_driverinfo.banner.style	      = UI_CENTER;

    s_driverinfo.framel.generic.type  = MTYPE_BITMAP;
    s_driverinfo.framel.generic.name  = DRIVERINFO_FRAMEL;
    s_driverinfo.framel.generic.flags = QMF_INACTIVE;
    s_driverinfo.framel.generic.x	  = 0;
    s_driverinfo.framel.generic.y	  = 78;
    s_driverinfo.framel.width  	      = 256;
    s_driverinfo.framel.height  	  = 329;

    s_driverinfo.framer.generic.type  = MTYPE_BITMAP;
    s_driverinfo.framer.generic.name  = DRIVERINFO_FRAMER;
    s_driverinfo.framer.generic.flags = QMF_INACTIVE;
    s_driverinfo.framer.generic.x	  = 376;
    s_driverinfo.framer.generic.y	  = 76;
    s_driverinfo.framer.width  	      = 256;
    s_driverinfo.framer.height  	  = 334;

    s_driverinfo.back.generic.type	   = MTYPE_BITMAP;
    s_driverinfo.back.generic.name     = DRIVERINFO_BACK0;
    s_driverinfo.back.generic.flags    = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS;
    s_driverinfo.back.generic.callback = DriverInfo_Event;
    s_driverinfo.back.generic.id	   = ID_DRIVERINFOBACK;
    s_driverinfo.back.generic.x		   = 0;
    s_driverinfo.back.generic.y		   = 480-64;
    s_driverinfo.back.width  		   = 128;
    s_driverinfo.back.height  		   = 64;
    s_driverinfo.back.focuspic         = DRIVERINFO_BACK1;

    // TTimo: overflow with particularly long GL extensions (such as the gf3)
    // https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=399
    // NOTE: could have pushed the size of stringbuff, but the list is already out of the screen
    // (no matter what your resolution)
    Q_strncpyz(s_driverinfo.stringbuff, uis.glconfig.extensions_string, 1024);

    // build null terminated extension strings
    eptr = s_driverinfo.stringbuff;
    while ( s_driverinfo.numstrings<40 && *eptr )
    {
        while ( *eptr && *eptr == ' ' )
            *eptr++ = '\0';

        // track start of valid string
        if (*eptr && *eptr != ' ')
            s_driverinfo.strings[s_driverinfo.numstrings++] = eptr;

        while ( *eptr && *eptr != ' ' )
            eptr++;
    }

    // safety length strings for display
    for (i=0; i<s_driverinfo.numstrings; i++)
    {
        len = strlen(s_driverinfo.strings[i]);
        if (len > 32)
        {
            s_driverinfo.strings[i][len-1] = '>';
            s_driverinfo.strings[i][len]   = '\0';
        }
    }

    Menu_AddItem( &s_driverinfo.menu, &s_driverinfo.banner );
    Menu_AddItem( &s_driverinfo.menu, &s_driverinfo.framel );
    Menu_AddItem( &s_driverinfo.menu, &s_driverinfo.framer );
    Menu_AddItem( &s_driverinfo.menu, &s_driverinfo.back );

    UI_PushMenu( &s_driverinfo.menu );
}

/*
=======================================================================
 
GRAPHICS OPTIONS MENU
 
=======================================================================
*/

#define GRAPHICSOPTIONS_FRAMEL	"menu/art/frame2_l"
#define GRAPHICSOPTIONS_FRAMER	"menu/art/frame1_r"
#define GRAPHICSOPTIONS_BACK0	"menu/art/back_0"
#define GRAPHICSOPTIONS_BACK1	"menu/art/back_1"
#define GRAPHICSOPTIONS_ACCEPT0	"menu/art/accept_0"
#define GRAPHICSOPTIONS_ACCEPT1	"menu/art/accept_1"

static const char *s_drivers[] =
    {
        OPENGL_DRIVER_NAME,
        _3DFX_DRIVER_NAME,
        0
    };

#define ID_BACK2		101
#define ID_FULLSCREEN	102
#define ID_LIST			103
#define ID_MODE			104
#define ID_DRIVERINFO	105
#define ID_GRAPHICS		106
#define ID_DISPLAY		107
#define ID_SOUND		108
#define ID_NETWORK		109

typedef struct
{
    menuframework_s	menu;

    menutext_s		banner;
    menubitmap_s	framel;
    menubitmap_s	framer;

    menutext_s		graphics;
    menutext_s		display;
    menutext_s		sound;
    menutext_s		network;

    menulist_s		list;
    menulist_s		mode;
    menulist_s		driver;
    menuslider_s	tq;
    menulist_s  	fs;
    menulist_s  	lighting;
    menulist_s  	allow_extensions;
    menulist_s  	texturebits;
    menulist_s  	colordepth;
    menulist_s  	geometry;
    menulist_s  	filter;
    menutext_s		driverinfo;

    menubitmap_s	apply;
    menubitmap_s	back;
}
graphicsoptions_t;

typedef struct
{
    int mode;
    qboolean fullscreen;
    int tq;
    int lighting;
    int colordepth;
    int texturebits;
    int geometry;
    int filter;
    int driver;
    qboolean extensions;
}
InitialVideoOptions_s;

static InitialVideoOptions_s	s_ivo;
static graphicsoptions_t		s_graphicsoptions;

static InitialVideoOptions_s s_ivo_templates[] =
    {
        {
            4, qtrue, 2, 0, 2, 2, 1, 1, 0, qtrue	// JDC: this was tq 3
        },
        {
            3, qtrue, 2, 0, 0, 0, 1, 0, 0, qtrue
        },
        {
            2, qtrue, 1, 0, 1, 0, 0, 0, 0, qtrue
        },
        {
            2, qtrue, 1, 1, 1, 0, 0, 0, 0, qtrue
        },
        {
            3, qtrue, 1, 0, 0, 0, 1, 0, 0, qtrue
        }
    };

#define NUM_IVO_TEMPLATES ( sizeof( s_ivo_templates ) / sizeof( s_ivo_templates[0] ) )

/*
=================
GraphicsOptions_GetInitialVideo
=================
*/
static void GraphicsOptions_GetInitialVideo( void )
{
    s_ivo.colordepth  = s_graphicsoptions.colordepth.curvalue;
    s_ivo.driver      = s_graphicsoptions.driver.curvalue;
    s_ivo.mode        = s_graphicsoptions.mode.curvalue;
    s_ivo.fullscreen  = s_graphicsoptions.fs.curvalue;
    s_ivo.extensions  = s_graphicsoptions.allow_extensions.curvalue;
    s_ivo.tq          = s_graphicsoptions.tq.curvalue;
    s_ivo.lighting    = s_graphicsoptions.lighting.curvalue;
    s_ivo.geometry    = s_graphicsoptions.geometry.curvalue;
    s_ivo.filter      = s_graphicsoptions.filter.curvalue;
    s_ivo.texturebits = s_graphicsoptions.texturebits.curvalue;
}

/*
=================
GraphicsOptions_CheckConfig
=================
*/
static void GraphicsOptions_CheckConfig( void )
{
    int i;

    for ( i = 0; i < NUM_IVO_TEMPLATES; i++ )
    {
        if ( s_ivo_templates[i].colordepth != s_graphicsoptions.colordepth.curvalue )
            continue;
        if ( s_ivo_templates[i].driver != s_graphicsoptions.driver.curvalue )
            continue;
        if ( s_ivo_templates[i].mode != s_graphicsoptions.mode.curvalue )
            continue;
        if ( s_ivo_templates[i].fullscreen != s_graphicsoptions.fs.curvalue )
            continue;
        if ( s_ivo_templates[i].tq != s_graphicsoptions.tq.curvalue )
            continue;
        if ( s_ivo_templates[i].lighting != s_graphicsoptions.lighting.curvalue )
            continue;
        if ( s_ivo_templates[i].geometry != s_graphicsoptions.geometry.curvalue )
            continue;
        if ( s_ivo_templates[i].filter != s_graphicsoptions.filter.curvalue )
            continue;
//		if ( s_ivo_templates[i].texturebits != s_graphicsoptions.texturebits.curvalue )
//			continue;
        s_graphicsoptions.list.curvalue = i;
        return;
    }
    s_graphicsoptions.list.curvalue = 4;
}

/*
=================
GraphicsOptions_UpdateMenuItems
=================
*/
static void GraphicsOptions_UpdateMenuItems( void )
{
    if ( s_graphicsoptions.driver.curvalue == 1 )
    {
        s_graphicsoptions.fs.curvalue = 1;
        s_graphicsoptions.fs.generic.flags |= QMF_GRAYED;
        s_graphicsoptions.colordepth.curvalue = 1;
    }
    else
    {
        s_graphicsoptions.fs.generic.flags &= ~QMF_GRAYED;
    }

    if ( s_graphicsoptions.fs.curvalue == 0 || s_graphicsoptions.driver.curvalue == 1 )
    {
        s_graphicsoptions.colordepth.curvalue = 0;
        s_graphicsoptions.colordepth.generic.flags |= QMF_GRAYED;
    }
    else
    {
        s_graphicsoptions.colordepth.generic.flags &= ~QMF_GRAYED;
    }

    if ( s_graphicsoptions.allow_extensions.curvalue == 0 )
    {
        if ( s_graphicsoptions.texturebits.curvalue == 0 )
        {
            s_graphicsoptions.texturebits.curvalue = 1;
        }
    }

    s_graphicsoptions.apply.generic.flags |= QMF_HIDDEN|QMF_INACTIVE;

    if ( s_ivo.mode != s_graphicsoptions.mode.curvalue )
    {
        s_graphicsoptions.apply.generic.flags &= ~(QMF_HIDDEN|QMF_INACTIVE);
    }
    if ( s_ivo.fullscreen != s_graphicsoptions.fs.curvalue )
    {
        s_graphicsoptions.apply.generic.flags &= ~(QMF_HIDDEN|QMF_INACTIVE);
    }
    if ( s_ivo.extensions != s_graphicsoptions.allow_extensions.curvalue )
    {
        s_graphicsoptions.apply.generic.flags &= ~(QMF_HIDDEN|QMF_INACTIVE);
    }
    if ( s_ivo.tq != s_graphicsoptions.tq.curvalue )
    {
        s_graphicsoptions.apply.generic.flags &= ~(QMF_HIDDEN|QMF_INACTIVE);
    }
    if ( s_ivo.lighting != s_graphicsoptions.lighting.curvalue )
    {
        s_graphicsoptions.apply.generic.flags &= ~(QMF_HIDDEN|QMF_INACTIVE);
    }
    if ( s_ivo.colordepth != s_graphicsoptions.colordepth.curvalue )
    {
        s_graphicsoptions.apply.generic.flags &= ~(QMF_HIDDEN|QMF_INACTIVE);
    }
    if ( s_ivo.driver != s_graphicsoptions.driver.curvalue )
    {
        s_graphicsoptions.apply.generic.flags &= ~(QMF_HIDDEN|QMF_INACTIVE);
    }
    if ( s_ivo.texturebits != s_graphicsoptions.texturebits.curvalue )
    {
        s_graphicsoptions.apply.generic.flags &= ~(QMF_HIDDEN|QMF_INACTIVE);
    }
    if ( s_ivo.geometry != s_graphicsoptions.geometry.curvalue )
    {
        s_graphicsoptions.apply.generic.flags &= ~(QMF_HIDDEN|QMF_INACTIVE);
    }
    if ( s_ivo.filter != s_graphicsoptions.filter.curvalue )
    {
        s_graphicsoptions.apply.generic.flags &= ~(QMF_HIDDEN|QMF_INACTIVE);
    }

    GraphicsOptions_CheckConfig();
}

/*
=================
GraphicsOptions_ApplyChanges
=================
*/
static void GraphicsOptions_ApplyChanges( void *unused, int notification )
{
    if (notification != QM_ACTIVATED)
        return;

    switch ( s_graphicsoptions.texturebits.curvalue  )
    {
    case 0:
        Cvar_SetValue( "r_texturebits", 0 );
        break;
    case 1:
        Cvar_SetValue( "r_texturebits", 16 );
        break;
    case 2:
        Cvar_SetValue( "r_texturebits", 32 );
        break;
    }
    Cvar_SetValue( "r_picmip", 3 - s_graphicsoptions.tq.curvalue );
    Cvar_SetValue( "r_allowExtensions", s_graphicsoptions.allow_extensions.curvalue );
    Cvar_SetValue( "r_mode", s_graphicsoptions.mode.curvalue );
    Cvar_SetValue( "r_fullscreen", s_graphicsoptions.fs.curvalue );
    Cvar_Set( "r_glDriver", ( char * ) s_drivers[s_graphicsoptions.driver.curvalue] );
    switch ( s_graphicsoptions.colordepth.curvalue )
    {
    case 0:
        Cvar_SetValue( "r_colorbits", 0 );
        Cvar_SetValue( "r_depthbits", 0 );
        Cvar_SetValue( "r_stencilbits", 0 );
        break;
    case 1:
        Cvar_SetValue( "r_colorbits", 16 );
        Cvar_SetValue( "r_depthbits", 16 );
        Cvar_SetValue( "r_stencilbits", 0 );
        break;
    case 2:
        Cvar_SetValue( "r_colorbits", 32 );
        Cvar_SetValue( "r_depthbits", 24 );
        break;
    }
    Cvar_SetValue( "r_vertexLight", s_graphicsoptions.lighting.curvalue );

    if ( s_graphicsoptions.geometry.curvalue == 2 )
    {
        Cvar_SetValue( "r_lodBias", 0 );
        Cvar_SetValue( "r_subdivisions", 4 );
    }
    else if ( s_graphicsoptions.geometry.curvalue == 1 )
    {
        Cvar_SetValue( "r_lodBias", 1 );
        Cvar_SetValue( "r_subdivisions", 12 );
    }
    else
    {
        Cvar_SetValue( "r_lodBias", 1 );
        Cvar_SetValue( "r_subdivisions", 20 );
    }

    if ( s_graphicsoptions.filter.curvalue )
    {
        Cvar_Set( "r_textureMode", "GL_LINEAR_MIPMAP_LINEAR" );
    }
    else
    {
        Cvar_Set( "r_textureMode", "GL_LINEAR_MIPMAP_NEAREST" );
    }

    Cbuf_ExecuteText( EXEC_APPEND, "vid_restart\n" );
}

/*
=================
GraphicsOptions_Event
=================
*/
static void GraphicsOptions_Event( void* ptr, int event )
{
    InitialVideoOptions_s *ivo;

    if( event != QM_ACTIVATED )
    {
        return;
    }

    switch( ((menucommon_s*)ptr)->id )
    {
    case ID_MODE:
        // clamp 3dfx video modes
        if ( s_graphicsoptions.driver.curvalue == 1 )
        {
            if ( s_graphicsoptions.mode.curvalue < 2 )
                s_graphicsoptions.mode.curvalue = 2;
            else if ( s_graphicsoptions.mode.curvalue > 6 )
                s_graphicsoptions.mode.curvalue = 6;
        }
        break;

    case ID_LIST:
        ivo = &s_ivo_templates[s_graphicsoptions.list.curvalue];

        s_graphicsoptions.mode.curvalue        = ivo->mode;
        s_graphicsoptions.tq.curvalue          = ivo->tq;
        s_graphicsoptions.lighting.curvalue    = ivo->lighting;
        s_graphicsoptions.colordepth.curvalue  = ivo->colordepth;
        s_graphicsoptions.texturebits.curvalue = ivo->texturebits;
        s_graphicsoptions.geometry.curvalue    = ivo->geometry;
        s_graphicsoptions.filter.curvalue      = ivo->filter;
        s_graphicsoptions.fs.curvalue          = ivo->fullscreen;
        break;

    case ID_DRIVERINFO:
        UI_DriverInfo_Menu();
        break;

    case ID_BACK2:
        UI_PopMenu();
        break;

    case ID_GRAPHICS:
        break;

    case ID_DISPLAY:
        UI_PopMenu();
        UI_DisplayOptionsMenu();
        break;

    case ID_SOUND:
        UI_PopMenu();
        UI_SoundOptionsMenu();
        break;

    case ID_NETWORK:
        UI_PopMenu();
        UI_NetworkOptionsMenu();
        break;
    }
}


/*
================
GraphicsOptions_TQEvent
================
*/
static void GraphicsOptions_TQEvent( void *ptr, int event )
{
    if( event != QM_ACTIVATED )
    {
        return;
    }
    s_graphicsoptions.tq.curvalue = (int)(s_graphicsoptions.tq.curvalue + 0.5);
}


/*
================
GraphicsOptions_MenuDraw
================
*/
void GraphicsOptions_MenuDraw (void)
{
//APSFIX - rework this
    GraphicsOptions_UpdateMenuItems();

    Menu_Draw( &s_graphicsoptions.menu );
}

/*
=================
GraphicsOptions_SetMenuItems
=================
*/
static void GraphicsOptions_SetMenuItems( void )
{
    s_graphicsoptions.mode.curvalue = Cvar_VariableValue( "r_mode" );
    if ( s_graphicsoptions.mode.curvalue < 0 )
    {
        s_graphicsoptions.mode.curvalue = 3;
    }
    s_graphicsoptions.fs.curvalue = Cvar_VariableValue("r_fullscreen");
    s_graphicsoptions.allow_extensions.curvalue = Cvar_VariableValue("r_allowExtensions");
    s_graphicsoptions.tq.curvalue = 3-Cvar_VariableValue( "r_picmip");
    if ( s_graphicsoptions.tq.curvalue < 0 )
    {
        s_graphicsoptions.tq.curvalue = 0;
    }
    else if ( s_graphicsoptions.tq.curvalue > 3 )
    {
        s_graphicsoptions.tq.curvalue = 3;
    }

    s_graphicsoptions.lighting.curvalue = Cvar_VariableValue( "r_vertexLight" ) != 0;
    switch ( ( int ) Cvar_VariableValue( "r_texturebits" ) )
    {
    default:
    case 0:
        s_graphicsoptions.texturebits.curvalue = 0;
        break;
    case 16:
        s_graphicsoptions.texturebits.curvalue = 1;
        break;
    case 32:
        s_graphicsoptions.texturebits.curvalue = 2;
        break;
    }

    if ( !Q_stricmp( UI_Cvar_VariableString( "r_textureMode" ), "GL_LINEAR_MIPMAP_NEAREST" ) )
    {
        s_graphicsoptions.filter.curvalue = 0;
    }
    else
    {
        s_graphicsoptions.filter.curvalue = 1;
    }

    if ( Cvar_VariableValue( "r_lodBias" ) > 0 )
    {
        if ( Cvar_VariableValue( "r_subdivisions" ) >= 20 )
        {
            s_graphicsoptions.geometry.curvalue = 0;
        }
        else
        {
            s_graphicsoptions.geometry.curvalue = 1;
        }
    }
    else
    {
        s_graphicsoptions.geometry.curvalue = 2;
    }

    switch ( ( int ) Cvar_VariableValue( "r_colorbits" ) )
    {
    default:
    case 0:
        s_graphicsoptions.colordepth.curvalue = 0;
        break;
    case 16:
        s_graphicsoptions.colordepth.curvalue = 1;
        break;
    case 32:
        s_graphicsoptions.colordepth.curvalue = 2;
        break;
    }

    if ( s_graphicsoptions.fs.curvalue == 0 )
    {
        s_graphicsoptions.colordepth.curvalue = 0;
    }
    if ( s_graphicsoptions.driver.curvalue == 1 )
    {
        s_graphicsoptions.colordepth.curvalue = 1;
    }
}

/*
================
GraphicsOptions_MenuInit
================
*/
void GraphicsOptions_MenuInit( void )
{
    static const char *s_driver_names[] =
        {
            "Default",
            "Voodoo",
            0
        };

    static const char *tq_names[] =
        {
            "Default",
            "16 bit",
            "32 bit",
            0
        };

    static const char *s_graphics_options_names[] =
        {
            "High Quality",
            "Normal",
            "Fast",
            "Fastest",
            "Custom",
            0
        };

    static const char *lighting_names[] =
        {
            "Lightmap",
            "Vertex",
            0
        };

    static const char *colordepth_names[] =
        {
            "Default",
            "16 bit",
            "32 bit",
            0
        };

    static const char *resolutions[] =
        {
            "320x240",
            "400x300",
            "512x384",
            "640x480",
            "800x600",
            "960x720",
            "1024x768",
            "1152x864",
            "1280x1024",
            "1600x1200",
            "2048x1536",
            "856x480 wide screen",
            0
        };
    static const char *filter_names[] =
        {
            "Bilinear",
            "Trilinear",
            0
        };
    static const char *quality_names[] =
        {
            "Low",
            "Medium",
            "High",
            0
        };
    static const char *enabled_names[] =
        {
            "Off",
            "On",
            0
        };

    int y;

    // zero set all our globals
    memset( &s_graphicsoptions, 0 ,sizeof(graphicsoptions_t) );

    GraphicsOptions_Cache();

    s_graphicsoptions.menu.wrapAround = qtrue;
    s_graphicsoptions.menu.fullscreen = qtrue;
    s_graphicsoptions.menu.draw       = GraphicsOptions_MenuDraw;

    s_graphicsoptions.banner.generic.type  = MTYPE_BTEXT;
    s_graphicsoptions.banner.generic.x	   = 320;
    s_graphicsoptions.banner.generic.y	   = 16;
    s_graphicsoptions.banner.string  	   = "SYSTEM SETUP";
    s_graphicsoptions.banner.color         = color_white;
    s_graphicsoptions.banner.style         = UI_CENTER;

    s_graphicsoptions.framel.generic.type  = MTYPE_BITMAP;
    s_graphicsoptions.framel.generic.name  = GRAPHICSOPTIONS_FRAMEL;
    s_graphicsoptions.framel.generic.flags = QMF_INACTIVE;
    s_graphicsoptions.framel.generic.x	   = 0;
    s_graphicsoptions.framel.generic.y	   = 78;
    s_graphicsoptions.framel.width  	   = 256;
    s_graphicsoptions.framel.height  	   = 329;

    s_graphicsoptions.framer.generic.type  = MTYPE_BITMAP;
    s_graphicsoptions.framer.generic.name  = GRAPHICSOPTIONS_FRAMER;
    s_graphicsoptions.framer.generic.flags = QMF_INACTIVE;
    s_graphicsoptions.framer.generic.x	   = 376;
    s_graphicsoptions.framer.generic.y	   = 76;
    s_graphicsoptions.framer.width  	   = 256;
    s_graphicsoptions.framer.height  	   = 334;

    s_graphicsoptions.graphics.generic.type		= MTYPE_PTEXT;
    s_graphicsoptions.graphics.generic.flags	= QMF_RIGHT_JUSTIFY;
    s_graphicsoptions.graphics.generic.id		= ID_GRAPHICS;
    s_graphicsoptions.graphics.generic.callback	= GraphicsOptions_Event;
    s_graphicsoptions.graphics.generic.x		= 216;
    s_graphicsoptions.graphics.generic.y		= 240 - 2 * PROP_HEIGHT;
    s_graphicsoptions.graphics.string			= "GRAPHICS";
    s_graphicsoptions.graphics.style			= UI_RIGHT;
    s_graphicsoptions.graphics.color			= color_red;

    s_graphicsoptions.display.generic.type		= MTYPE_PTEXT;
    s_graphicsoptions.display.generic.flags		= QMF_RIGHT_JUSTIFY|QMF_PULSEIFFOCUS;
    s_graphicsoptions.display.generic.id		= ID_DISPLAY;
    s_graphicsoptions.display.generic.callback	= GraphicsOptions_Event;
    s_graphicsoptions.display.generic.x			= 216;
    s_graphicsoptions.display.generic.y			= 240 - PROP_HEIGHT;
    s_graphicsoptions.display.string			= "DISPLAY";
    s_graphicsoptions.display.style				= UI_RIGHT;
    s_graphicsoptions.display.color				= color_red;

    s_graphicsoptions.sound.generic.type		= MTYPE_PTEXT;
    s_graphicsoptions.sound.generic.flags		= QMF_RIGHT_JUSTIFY|QMF_PULSEIFFOCUS;
    s_graphicsoptions.sound.generic.id			= ID_SOUND;
    s_graphicsoptions.sound.generic.callback	= GraphicsOptions_Event;
    s_graphicsoptions.sound.generic.x			= 216;
    s_graphicsoptions.sound.generic.y			= 240;
    s_graphicsoptions.sound.string				= "SOUND";
    s_graphicsoptions.sound.style				= UI_RIGHT;
    s_graphicsoptions.sound.color				= color_red;

    s_graphicsoptions.network.generic.type		= MTYPE_PTEXT;
    s_graphicsoptions.network.generic.flags		= QMF_RIGHT_JUSTIFY|QMF_PULSEIFFOCUS;
    s_graphicsoptions.network.generic.id		= ID_NETWORK;
    s_graphicsoptions.network.generic.callback	= GraphicsOptions_Event;
    s_graphicsoptions.network.generic.x			= 216;
    s_graphicsoptions.network.generic.y			= 240 + PROP_HEIGHT;
    s_graphicsoptions.network.string			= "NETWORK";
    s_graphicsoptions.network.style				= UI_RIGHT;
    s_graphicsoptions.network.color				= color_red;

    y = 240 - 6 * (BIGCHAR_HEIGHT + 2);
    s_graphicsoptions.list.generic.type     = MTYPE_SPINCONTROL;
    s_graphicsoptions.list.generic.name     = "Graphics Settings:";
    s_graphicsoptions.list.generic.flags    = QMF_PULSEIFFOCUS|QMF_SMALLFONT;
    s_graphicsoptions.list.generic.x        = 400;
    s_graphicsoptions.list.generic.y        = y;
    s_graphicsoptions.list.generic.callback = GraphicsOptions_Event;
    s_graphicsoptions.list.generic.id       = ID_LIST;
    s_graphicsoptions.list.itemnames        = s_graphics_options_names;
    y += 2 * ( BIGCHAR_HEIGHT + 2 );

    s_graphicsoptions.driver.generic.type  = MTYPE_SPINCONTROL;
    s_graphicsoptions.driver.generic.name  = "GL Driver:";
    s_graphicsoptions.driver.generic.flags = QMF_PULSEIFFOCUS|QMF_SMALLFONT;
    s_graphicsoptions.driver.generic.x     = 400;
    s_graphicsoptions.driver.generic.y     = y;
    s_graphicsoptions.driver.itemnames     = s_driver_names;
    s_graphicsoptions.driver.curvalue      = (uis.glconfig.driverType == GLDRV_VOODOO);
    y += BIGCHAR_HEIGHT+2;

    // references/modifies "r_allowExtensions"
    s_graphicsoptions.allow_extensions.generic.type     = MTYPE_SPINCONTROL;
    s_graphicsoptions.allow_extensions.generic.name	    = "GL Extensions:";
    s_graphicsoptions.allow_extensions.generic.flags	= QMF_PULSEIFFOCUS|QMF_SMALLFONT;
    s_graphicsoptions.allow_extensions.generic.x	    = 400;
    s_graphicsoptions.allow_extensions.generic.y	    = y;
    s_graphicsoptions.allow_extensions.itemnames        = enabled_names;
    y += BIGCHAR_HEIGHT+2;

    // references/modifies "r_mode"
    s_graphicsoptions.mode.generic.type     = MTYPE_SPINCONTROL;
    s_graphicsoptions.mode.generic.name     = "Video Mode:";
    s_graphicsoptions.mode.generic.flags    = QMF_PULSEIFFOCUS|QMF_SMALLFONT;
    s_graphicsoptions.mode.generic.x        = 400;
    s_graphicsoptions.mode.generic.y        = y;
    s_graphicsoptions.mode.itemnames        = resolutions;
    s_graphicsoptions.mode.generic.callback = GraphicsOptions_Event;
    s_graphicsoptions.mode.generic.id       = ID_MODE;
    y += BIGCHAR_HEIGHT+2;

    // references "r_colorbits"
    s_graphicsoptions.colordepth.generic.type     = MTYPE_SPINCONTROL;
    s_graphicsoptions.colordepth.generic.name     = "Color Depth:";
    s_graphicsoptions.colordepth.generic.flags    = QMF_PULSEIFFOCUS|QMF_SMALLFONT;
    s_graphicsoptions.colordepth.generic.x        = 400;
    s_graphicsoptions.colordepth.generic.y        = y;
    s_graphicsoptions.colordepth.itemnames        = colordepth_names;
    y += BIGCHAR_HEIGHT+2;

    // references/modifies "r_fullscreen"
    s_graphicsoptions.fs.generic.type     = MTYPE_SPINCONTROL;
    s_graphicsoptions.fs.generic.name	  = "Fullscreen:";
    s_graphicsoptions.fs.generic.flags	  = QMF_PULSEIFFOCUS|QMF_SMALLFONT;
    s_graphicsoptions.fs.generic.x	      = 400;
    s_graphicsoptions.fs.generic.y	      = y;
    s_graphicsoptions.fs.itemnames	      = enabled_names;
    y += BIGCHAR_HEIGHT+2;

    // references/modifies "r_vertexLight"
    s_graphicsoptions.lighting.generic.type  = MTYPE_SPINCONTROL;
    s_graphicsoptions.lighting.generic.name	 = "Lighting:";
    s_graphicsoptions.lighting.generic.flags = QMF_PULSEIFFOCUS|QMF_SMALLFONT;
    s_graphicsoptions.lighting.generic.x	 = 400;
    s_graphicsoptions.lighting.generic.y	 = y;
    s_graphicsoptions.lighting.itemnames     = lighting_names;
    y += BIGCHAR_HEIGHT+2;

    // references/modifies "r_lodBias" & "subdivisions"
    s_graphicsoptions.geometry.generic.type  = MTYPE_SPINCONTROL;
    s_graphicsoptions.geometry.generic.name	 = "Geometric Detail:";
    s_graphicsoptions.geometry.generic.flags = QMF_PULSEIFFOCUS|QMF_SMALLFONT;
    s_graphicsoptions.geometry.generic.x	 = 400;
    s_graphicsoptions.geometry.generic.y	 = y;
    s_graphicsoptions.geometry.itemnames     = quality_names;
    y += BIGCHAR_HEIGHT+2;

    // references/modifies "r_picmip"
    s_graphicsoptions.tq.generic.type	= MTYPE_SLIDER;
    s_graphicsoptions.tq.generic.name	= "Texture Detail:";
    s_graphicsoptions.tq.generic.flags	= QMF_PULSEIFFOCUS|QMF_SMALLFONT;
    s_graphicsoptions.tq.generic.x		= 400;
    s_graphicsoptions.tq.generic.y		= y;
    s_graphicsoptions.tq.minvalue       = 0;
    s_graphicsoptions.tq.maxvalue       = 3;
    s_graphicsoptions.tq.generic.callback = GraphicsOptions_TQEvent;
    y += BIGCHAR_HEIGHT+2;

    // references/modifies "r_textureBits"
    s_graphicsoptions.texturebits.generic.type  = MTYPE_SPINCONTROL;
    s_graphicsoptions.texturebits.generic.name	= "Texture Quality:";
    s_graphicsoptions.texturebits.generic.flags	= QMF_PULSEIFFOCUS|QMF_SMALLFONT;
    s_graphicsoptions.texturebits.generic.x	    = 400;
    s_graphicsoptions.texturebits.generic.y	    = y;
    s_graphicsoptions.texturebits.itemnames     = tq_names;
    y += BIGCHAR_HEIGHT+2;

    // references/modifies "r_textureMode"
    s_graphicsoptions.filter.generic.type   = MTYPE_SPINCONTROL;
    s_graphicsoptions.filter.generic.name	= "Texture Filter:";
    s_graphicsoptions.filter.generic.flags	= QMF_PULSEIFFOCUS|QMF_SMALLFONT;
    s_graphicsoptions.filter.generic.x	    = 400;
    s_graphicsoptions.filter.generic.y	    = y;
    s_graphicsoptions.filter.itemnames      = filter_names;
    y += 2*BIGCHAR_HEIGHT;

    s_graphicsoptions.driverinfo.generic.type     = MTYPE_PTEXT;
    s_graphicsoptions.driverinfo.generic.flags    = QMF_CENTER_JUSTIFY|QMF_PULSEIFFOCUS;
    s_graphicsoptions.driverinfo.generic.callback = GraphicsOptions_Event;
    s_graphicsoptions.driverinfo.generic.id       = ID_DRIVERINFO;
    s_graphicsoptions.driverinfo.generic.x        = 320;
    s_graphicsoptions.driverinfo.generic.y        = y;
    s_graphicsoptions.driverinfo.string           = "Driver Info";
    s_graphicsoptions.driverinfo.style            = UI_CENTER|UI_SMALLFONT;
    s_graphicsoptions.driverinfo.color            = color_red;
    y += BIGCHAR_HEIGHT+2;

    s_graphicsoptions.back.generic.type	    = MTYPE_BITMAP;
    s_graphicsoptions.back.generic.name     = GRAPHICSOPTIONS_BACK0;
    s_graphicsoptions.back.generic.flags    = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS;
    s_graphicsoptions.back.generic.callback = GraphicsOptions_Event;
    s_graphicsoptions.back.generic.id	    = ID_BACK2;
    s_graphicsoptions.back.generic.x		= 0;
    s_graphicsoptions.back.generic.y		= 480-64;
    s_graphicsoptions.back.width  		    = 128;
    s_graphicsoptions.back.height  		    = 64;
    s_graphicsoptions.back.focuspic         = GRAPHICSOPTIONS_BACK1;

    s_graphicsoptions.apply.generic.type     = MTYPE_BITMAP;
    s_graphicsoptions.apply.generic.name     = GRAPHICSOPTIONS_ACCEPT0;
    s_graphicsoptions.apply.generic.flags    = QMF_RIGHT_JUSTIFY|QMF_PULSEIFFOCUS|QMF_HIDDEN|QMF_INACTIVE;
    s_graphicsoptions.apply.generic.callback = GraphicsOptions_ApplyChanges;
    s_graphicsoptions.apply.generic.x        = 640;
    s_graphicsoptions.apply.generic.y        = 480-64;
    s_graphicsoptions.apply.width  		     = 128;
    s_graphicsoptions.apply.height  		 = 64;
    s_graphicsoptions.apply.focuspic         = GRAPHICSOPTIONS_ACCEPT1;

    Menu_AddItem( &s_graphicsoptions.menu, ( void * ) &s_graphicsoptions.banner );
    Menu_AddItem( &s_graphicsoptions.menu, ( void * ) &s_graphicsoptions.framel );
    Menu_AddItem( &s_graphicsoptions.menu, ( void * ) &s_graphicsoptions.framer );

    Menu_AddItem( &s_graphicsoptions.menu, ( void * ) &s_graphicsoptions.graphics );
    Menu_AddItem( &s_graphicsoptions.menu, ( void * ) &s_graphicsoptions.display );
    Menu_AddItem( &s_graphicsoptions.menu, ( void * ) &s_graphicsoptions.sound );
    Menu_AddItem( &s_graphicsoptions.menu, ( void * ) &s_graphicsoptions.network );

    Menu_AddItem( &s_graphicsoptions.menu, ( void * ) &s_graphicsoptions.list );
    Menu_AddItem( &s_graphicsoptions.menu, ( void * ) &s_graphicsoptions.driver );
    Menu_AddItem( &s_graphicsoptions.menu, ( void * ) &s_graphicsoptions.allow_extensions );
    Menu_AddItem( &s_graphicsoptions.menu, ( void * ) &s_graphicsoptions.mode );
    Menu_AddItem( &s_graphicsoptions.menu, ( void * ) &s_graphicsoptions.colordepth );
    Menu_AddItem( &s_graphicsoptions.menu, ( void * ) &s_graphicsoptions.fs );
    Menu_AddItem( &s_graphicsoptions.menu, ( void * ) &s_graphicsoptions.lighting );
    Menu_AddItem( &s_graphicsoptions.menu, ( void * ) &s_graphicsoptions.geometry );
    Menu_AddItem( &s_graphicsoptions.menu, ( void * ) &s_graphicsoptions.tq );
    Menu_AddItem( &s_graphicsoptions.menu, ( void * ) &s_graphicsoptions.texturebits );
    Menu_AddItem( &s_graphicsoptions.menu, ( void * ) &s_graphicsoptions.filter );
    Menu_AddItem( &s_graphicsoptions.menu, ( void * ) &s_graphicsoptions.driverinfo );

    Menu_AddItem( &s_graphicsoptions.menu, ( void * ) &s_graphicsoptions.back );
    Menu_AddItem( &s_graphicsoptions.menu, ( void * ) &s_graphicsoptions.apply );

    GraphicsOptions_SetMenuItems();
    GraphicsOptions_GetInitialVideo();

    if ( uis.glconfig.driverType == GLDRV_ICD &&
            uis.glconfig.hardwareType == GLHW_3DFX_2D3D )
    {
        s_graphicsoptions.driver.generic.flags |= QMF_HIDDEN|QMF_INACTIVE;
    }
}


/*
=================
GraphicsOptions_Cache
=================
*/
void GraphicsOptions_Cache( void )
{
    RE_RegisterShaderNoMip( GRAPHICSOPTIONS_FRAMEL );
    RE_RegisterShaderNoMip( GRAPHICSOPTIONS_FRAMER );
    RE_RegisterShaderNoMip( GRAPHICSOPTIONS_BACK0 );
    RE_RegisterShaderNoMip( GRAPHICSOPTIONS_BACK1 );
    RE_RegisterShaderNoMip( GRAPHICSOPTIONS_ACCEPT0 );
    RE_RegisterShaderNoMip( GRAPHICSOPTIONS_ACCEPT1 );
}


/*
=================
UI_GraphicsOptionsMenu
=================
*/
void UI_GraphicsOptionsMenu( void )
{
    GraphicsOptions_MenuInit();
    UI_PushMenu( &s_graphicsoptions.menu );
    Menu_SetCursorToItem( &s_graphicsoptions.menu, &s_graphicsoptions.graphics );
}

